#include "bit.h"
#include "stream.h"

/*
 * NAME:	stream->init()
 * DESCRIPTION:	initialize stream struct
 */
void bits_stream_init(struct bits_stream *stream)
{
	stream->buffer = 0;
	stream->buffer_end = 0;
	stream->error = STREAM_ERROR_NONE;
	mad_bit_init(&stream->ptr,0);
}

/*
 * NAME:	stream->buffer()
 * DESCRIPTION:	set stream buffer pointers
 */
void bits_stream_buffer(struct bits_stream *stream,unsigned char const *buffer,unsigned long length)
{
	stream->buffer = buffer;
	stream->buffer_end = buffer + length;
	mad_bit_init(&stream->ptr,buffer);
	stream->i_bits = length * CHAR_BIT;
}

unsigned long bits_stream_read(struct bits_stream *stream,unsigned int ibits)
{
	unsigned long ival = 0;
	do {
		if(stream->i_bits < ibits) {
			stream->error = STREAM_ERROR_BUFPTR;
			break;
		}
		ival = mad_bit_read(&stream->ptr,ibits);
		stream->i_bits -= ibits;
		
	} while(0);
	return ival;
}

void bits_stream_skip(struct bits_stream *stream,unsigned int len)
{
	if(stream->i_bits < len) {
		stream->error = STREAM_ERROR_BUFPTR;	
	}
	else {
		mad_bit_skip(&stream->ptr,len);
		stream->i_bits -= len;
	}
}

struct bits_code * bits_stream_decNum(struct bits_stream *stream,struct bits_code *pbitCode,unsigned char ibitCode,unsigned long *p_ulval)
{
	unsigned long ul_val = 0;
	do {
		int readbits = 0;
		unsigned short wCode = 0;
		struct bits_stream streamTemp = *stream;
		int i = 0;
		if(!pbitCode || ibitCode <= 0) {
			stream->error = STREAM_ERROR_NODECODE;	
			break;
		}
		readbits = 16;
		wCode = (unsigned short)bits_stream_read(&streamTemp,readbits);
		for(;i < ibitCode;i++,pbitCode++) {
			if(pbitCode->wval_code_bits == (wCode >> (readbits - pbitCode->bval_code_len))) {
				break;
			}
		}
		if(i == ibitCode)
		{
			stream->error = STREAM_ERROR_NODECODE;	
			break;
		}
		bits_stream_skip(stream,pbitCode->bval_code_len);
		if(pbitCode->bval_data_len > 0) {
			ul_val = (unsigned long)bits_stream_read(stream,pbitCode->bval_data_len);
		}
		if(pbitCode->cval_data_type == 'C')			// const
			ul_val = pbitCode->dwval_data_bias;
		else if(pbitCode->cval_data_type == 'D')		// DWORD
			ul_val = ul_val + pbitCode->dwval_data_bias;
		else if(pbitCode->cval_data_type == 'I')		// INT
		{
			if(ul_val >> (pbitCode->bval_data_len - 1)) {
				ul_val |= (0xFFFFFFFF << pbitCode->bval_data_len);
				ul_val = ul_val - pbitCode->dwval_data_bias;
			}
			else
				ul_val = ul_val + pbitCode->dwval_data_bias;
		}
		else if(pbitCode->cval_data_type == 'H')		// HUNDRED
			ul_val = (ul_val + pbitCode->dwval_data_bias) * 100;
		else if(pbitCode->cval_data_type == 'h')		// HUNDRED INT
		{
			if(ul_val >> (pbitCode->bval_data_len - 1)) {
				ul_val |= (0xFFFFFFFF << pbitCode->bval_data_len);
				ul_val = (ul_val - pbitCode->dwval_data_bias) * 100;		
			}
			else {
				ul_val = (ul_val + pbitCode->dwval_data_bias) * 100;
			}
		}	
		if(p_ulval) {
			*p_ulval = ul_val;
		}
		return pbitCode;
		
	} while(0);
	
	return 0;	
}

unsigned long bits_stream_decData(struct bits_stream *stream,struct bits_code *pbitCode,unsigned char ibitCode,unsigned long *p_ulBase,unsigned char bINC)
{
	unsigned long ulVal = 0;
	struct bits_code *pbitsCode = bits_stream_decNum(stream,pbitCode,ibitCode,&ulVal);
	if(pbitsCode) {
		if(pbitsCode->cval_data_type != 'O' && p_ulBase) {
			if(bINC) {
				ulVal += *p_ulBase;
			}
			else {
				ulVal = *p_ulBase - ulVal;
			}
		}
	}
	return ulVal;
}

int bits_stream_decXINT32(struct bits_stream *stream,struct bits_code *pbitCode,unsigned char ibitCode,XINT32 *pxval_out,XINT32 *pxval_base,unsigned char bdes)
{
	int ival = 0;
	unsigned long idecNum = 0; 
	pbitCode = bits_stream_decNum(stream, pbitCode, ibitCode, &idecNum);
	if(pbitCode) {
		if(pbitCode->cval_data_type == 'O') {
			XINT32_INIT_INT32(pxval_out,idecNum);
		}
		else 
		{
			if(pxval_base) {
				if(bdes) {
					XINT32_INIT_INT64(pxval_out,XINT32_VALINT64(pxval_base) - idecNum);
				}
				else {
					XINT32_INIT_INT64(pxval_out,XINT32_VALINT64(pxval_base) + idecNum);
				}
			}
			else {
				XINT32_INIT_INT64(pxval_out,idecNum);
			}
		}
		ival++;
	}
	return ival;
}

/* unsigned char bits_stream_decode_data(struct bits_stream *stream,unsigned long *p_ulData,struct bits_code *pbitCode,unsigned char ibitCode,unsigned long *pdwbase,unsigned char bReverse)
 {	
 unsigned char cbytes = 0;
 struct bits_code *pCode = bits_stream_decode(stream,pbitCode,ibitCode,p_ulData,&cbytes);
 if(pCode)
 {
 if(pCode->cval_data_type != 'O' && pdwbase)
 {
 if(bReverse) {
 *p_ulData = *pdwbase - *p_ulData;
 }
 else {
 *p_ulData = *pdwbase + *p_ulData;
 }
 }
 }
 return cbytes;
 } */

